package com.mike.bdb.util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mike.bdb.manager.DBManager;
import com.mike.bdb.ui.ImportDialog;
import com.mike.bdb.ui.MainWindow;
import com.mike.bdb.ui.support.AbstractBackGroundWorkDialog;
import com.sleepycat.persist.EntityCursor;

public class BackThread extends Thread {
	
	private static final Logger LOG = LoggerFactory.getLogger(BackThread.class);
	
	public static final int OK_VALUE = AbstractBackGroundWorkDialog.FINISH_SELECTION;

	private static final Charset FILE_CHARSET = Charset.forName("UTF-8");
	private static final String FILE_START_FLAG = "CLASS:";

	private long	updateInternal = 100;
	
	/** 导出数据 */
	public void doExportWork() {
		
		String dataBasePath = DataCurrent.getInstance().curDataBasePath;
		if(null == dataBasePath) return;
		
		String curStoreClazz = DataCurrent.getInstance().curStoreClazz;
		if(null == curStoreClazz) return;
		
		if(LOG.isDebugEnabled()) {
			LOG.debug("Ready to export database:" + dataBasePath);
			LOG.debug("export class:" + curStoreClazz);
		}
		
		Class<Object> classBy = ReflectUtil.getClassBy(curStoreClazz);
		if(null == classBy) return;
		
		Class pkClass = ReflectUtil.getPKClass(classBy);
		
		long allCount = DBManager.getInstance().getPKStore(pkClass, classBy).count();
		EntityCursor<?> entities = DBManager.getInstance().getPKStore(pkClass, classBy).entities();
		
		String name = IMPORT_FILE_SUFFIX;
		
		name =  dataBasePath + 
			File.separator + 
			IMPORT_FOLDER;
		Folder.getFolder(name);
		
		String n = IMPORT_FILE_SUFFIX;
		name += File.separator + 
			n.replace("*", classBy.getSimpleName());
		
		if(LOG.isDebugEnabled()) {
			LOG.debug("Export File to:" + name);
		}
		
		File exportFile = Folder.getNewFile(name);
		
		writerToFile(exportFile, entities, allCount);
		
		entities.close();
	}

	private void writerToFile(File exportFile, EntityCursor<?> entities, long allCount) {
		if(null == exportFile) return;
		if(null == entities) return;
		try {
			BufferedWriter bw = new BufferedWriter(
					new OutputStreamWriter(
							new FileOutputStream(exportFile), FILE_CHARSET));
			updateProgressPercent(0.1f);
			bw.append(FILE_START_FLAG + DataCurrent.getInstance().curStoreClazz);
			bw.newLine();
			bw.append(FILE_START_FLAG + allCount);
			bw.newLine();
			long index = 1;
			for (Object o : entities) {
				bw.append(JSONUtil.getJSONObjStr(o));
				bw.newLine();
				index++;
				if(index % updateInternal == 0)
					updateProgressPercent((float) index / allCount);
			}
			bw.flush();
			bw.close();
			progress = OK_VALUE;
		} catch (Exception e) {
			if(LOG.isDebugEnabled()) {
				LOG.debug("export Exception" + e.getMessage());
			}
		}
	}

	/** 导入数据的文件类型 */
	public static final String IMPORT_FOLDER = "export";
	public static final String IMPORT_FILE_SUFFIX = "*.mike";
	/** 导入数据 */
	public void doImportWork() {
		File curImportFile = DataCurrent.getInstance().curImportFile;
		if(null == curImportFile) return;
		if(LOG.isDebugEnabled()) {
			LOG.debug("Import From File:" + curImportFile.getAbsolutePath());
		}
		
		try {
			BufferedReader br = new BufferedReader(
					new InputStreamReader(
							new FileInputStream(curImportFile), FILE_CHARSET));
			String temp = "";
			String className = "";
			boolean readedFirst = false;
			boolean readedSecond = false;
			long allCount = 100;
			long index = 1;
			while(null != (temp = br.readLine())) {
				if(!readedFirst && temp.startsWith(FILE_START_FLAG)) {
					String[] split = temp.split(FILE_START_FLAG);
					if(split.length != 2) {
						br.close();
						return;
					}
					
					className = split[split.length - 1];
					
					readedFirst = true;
				} else if(!readedSecond && temp.startsWith(FILE_START_FLAG)) {
					String[] split = temp.split(FILE_START_FLAG);
					if(split.length != 2) {
						br.close();
						return;
					}
					try {
						allCount = Long.parseLong(split[split.length - 1]);
					} catch (Exception e) {
						//eat it;
					}
					
					readedSecond = true;
				} else {
					String curStoreClazz = DataCurrent.getInstance().curStoreClazz;
//					if(LOG.isDebugEnabled()) {
//						LOG.debug("curStorClazz:" + curStoreClazz);
//					}
					if(!className.equals(curStoreClazz)) {
						alert(className, curStoreClazz);
						return;
					}
					doEachJSONStr(temp, className);
					index++;
					if(index % updateInternal == 0)
						updateProgressPercent((float) index / allCount);
				}
			}
			br.close();
		} catch (Exception e) {
			if(LOG.isDebugEnabled()) {
				LOG.debug("import Exception" + e.getMessage());
			}
		}
		progress = OK_VALUE;
		Display dis = Display.getDefault();
		dis.asyncExec(new Runnable() {
			@Override
			public void run() {
				if(null != mainWindow) 
					mainWindow.refreshActiveViewer();
			}
		});
	}
	
	private void alert(final String importClassName, final String curClassName) {
		Display.getDefault().syncExec(new Runnable() {
			@Override
			public void run() {
				if(null != importDialog) {
					importDialog.close();
				}
				Shell shell = new Shell();
				MessageBox mb = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK);
				mb.setText("系统提示");
				mb.setMessage("不匹配的实体类导入数据文件\n\n"
						+ "导入文件是:" + ClassNameUtil.getSimpleName(importClassName) + "\n\n"
						+ "当前实体类:" + ClassNameUtil.getSimpleName(curClassName));
				mb.open();
			}
		});
	}

	private void doEachJSONStr(String temp, String className) {
		try {
			JSONObject json = new JSONObject(temp);
			String curStoreClazz = DataCurrent.getInstance().curStoreClazz;
			Class<Object> classBy = ReflectUtil.getClassBy(curStoreClazz);
			List<Method> berkeleyAttribute = ReflectUtil.getBerkeleyAttribute(classBy);
			Object newInstance = classBy.newInstance();
			
			HashMap<String, java.lang.reflect.Type> mapByListMethod = ReflectUtil.getMapByListMethod(berkeleyAttribute);
			
			for (Method method : berkeleyAttribute) {
				//TODO 需要重构 
				ReflectUtil.invokeSet(curStoreClazz, method.getName(), newInstance, json.get(method.getName()), mapByListMethod, false);
			}
			Class pkClass = ReflectUtil.getPKClass(classBy);
			//TODO ★ Berkeley DB put JSON
			DBManager.getInstance().getPKStore(pkClass, classBy).put(newInstance);
		} catch (Exception e) {
			//ignore
		}
	}

	private Type type;
	private MainWindow mainWindow;
	
	private int progress;

	private ImportDialog	importDialog;
	
	public int getProgress() {
		return progress;
	}

	public BackThread(Type type) {
		this.type = type;
	}
	
	public BackThread(Type type, MainWindow mainWindow, ImportDialog importDialog) {
		this.type = type;
		this.mainWindow = mainWindow;
		this.importDialog = importDialog;
	}
	
	protected void timeout() {
		try {
			TimeUnit.MILLISECONDS.sleep(10);
		} catch (InterruptedException e) {
			Thread.currentThread().interrupt();
		}
	}
	
	@Override
	public void run() {
		switch (type) {
			case Export:
				doExportWork();
				break;
			case Import:
				doImportWork();
				break;
		}
	}
	
	/**
	 * 进度更新 百分比
	 * @param percent	0 ~ 1 之间的一个小数
	 */
	private void updateProgressPercent(float percent) {
		if(percent >= 1)
			progress = OK_VALUE;
		if(percent < 0) 
			progress = 0;
		progress = Math.round(percent * 100);
	}
	
	public enum Type{
		/** 导出 */
		Export,	
		/** 导入 */
		Import	
	}
	
	
}
